import MessageBody from './MessageBody'
import SocketBus from './SocketBus'
import Direction from './Direction'
import Message from './Message';
import MessageType from './MessageType';
import SendStatusHash from './SendStatusHash';
import UuidGenerator from './UuidGenerator';
import SendStatus from './SendStatus';
import MsgCodec from './MsgCodec';
import MessageCommand from './MessageCommand';
import SortedHash from './SortedHash';
import MessageBodyCallback from './MessageBodyCallback';
import ServerAckCallback from './ServerAckCallback';
import axios from 'axios'

class MessageBus {
    public direction :Direction;
    public socketBus:SocketBus;
    private sendStatusHash!:SendStatusHash;
    public sortedHash!:SortedHash|null;
    private historyUrl!:string;
    private groupName!:string;
    public historySize!: number;
    public position!:number;

    constructor(direction: Direction, socketBus: SocketBus, historyUrl: string, groupName: string, historySize: number, position:number){
        let self = this;
        this.direction =  direction;
        this.socketBus = socketBus;        
        this.historyUrl = historyUrl;
        this.sendStatusHash = {};
        this.sortedHash = new SortedHash;
        this.groupName = groupName;
        this.socketBus.onMsg = (msg:string)=>{           
            self.onMessage(msg);
        };
        this.historySize = historySize;
        this.position = position;
        this.socketBus.onConnect = ()=>{
            console.debug("connected in MessageBus:"+this.socketBus._id);
            if(self.historySize>0){
                console.debug("historySize>0, try to fetch from history api")
                self.pullHistory();
            }
        };
        this.socketBus.connect();
        //this.pullHistory();
    }
    
    public pushMessage(msg:string){                       
        let messageBody :MessageBody ;  
        let uuid  = UuidGenerator.generate();  
        messageBody = new MessageBody(msg);
        let message :Message = {
            body:messageBody,
            type:MessageType.Data,
            uuid:uuid
        };

        this.sendStatusHash[uuid] = SendStatus.Default;
        if(this.sortedHash!=null){
            this.sortedHash.push(message);     
        }
        this.socketBus.send(message);
        let self = this;
        let timer = setTimeout(()=>{
            /**
             *  如果两条之内再检查状态，还是未发送，则重发一次；最多重发两次;
            */
           if(this.sendStatusHash[uuid]==SendStatus.Default){
               console.debug("resend msg because no  ServerACK not received")
               self.socketBus.send(message);
               setTimeout(()=>{
                    if(self.sendStatusHash[uuid]==SendStatus.Default){
                        /**
                         * @todo  需要通知外部，要显示异常信息了;
                         * 本来想删掉，觉得未送达时，还是应该保存，并置一个错误信息;
                         */
                        //self.sortedHash.markAsFailed(uuid);
                    }
               },3000);
           }
        },3000);
    }
    public onServerAck(uuid:string){
       // this.sortedHash.push();
    }
    private pullHistory() {
        let self = this;
        axios.request({
            url: this.historyUrl,
            method: "POST",
            params: {
                groupName: this.groupName,
                size: this.historySize,
                position:this.position
            }
        }).then((resp) => {
            if(self.sortedHash==null){
                return;
            }
            if(resp.data.data.length != self.sortedHash.size()){        
                self.sortedHash.reset();
                for (let itemJson of resp.data.data.reverse()) {
                    let msg = <Message>JSON.parse(itemJson)                   
                    if(msg.body){
                        msg.body.sent=true;
                    }
                    if(self.sortedHash!=null){
                        self.sortedHash.push(msg)
                    }
                }
            }
     
        }).catch(() => { });
    }

    public onMessage(messageStr:string ){        
        //先用msgpackDecode一下，
        let message;
        try{
         message = MsgCodec.decode(messageStr);
        }catch(e){
            console.debug("msgdecode failed:"+messageStr);
            //console.log(messageStr);
        }
        if(message == undefined){
            console.debug('json decode failed str:'+messageStr);
            return;
        }
        
        let self = this;
        if(message.type == MessageType.Data){
            /**
             *  @todo 追加到本地待显示队列中去;
             */ 
            if(this.sortedHash!=null){
                this.sortedHash.push(message);           
            }
        }
        if(message.type == MessageType.Command){
            switch(message.command){
                case MessageCommand.SERVER_ACK:
                    console.debug("got an ack msg");
                    self.sendStatusHash[message.uuid] = SendStatus.ServerReceived;
                    if(self.sortedHash!=null){
                        self.sortedHash.markAsServerAck(message.uuid);
                    }
                    break;
                case MessageCommand.CUSTOMER_ACK:
                case MessageCommand.WAITRESS_ACK:
                    self.sendStatusHash[message.uuid] = SendStatus.PeerSideReceived;
                case MessageCommand.QUERY:
                    //客户端是不负责回应QUERY相关的消息的;
                    break;
                case MessageCommand.PINGPONG:
                    console.debug("new pingpong:"+new Date());
                    //对于PingPong信息，完全忽略掉;
                    break;    
            }
        }
    }
    public all():MessageBody[]{
        if(this.sortedHash!=null){
            return this.sortedHash.all()
        }else{
            return [];
        }
    }
    public setNewMessageCallback(callback:MessageBodyCallback){
        if(this.sortedHash!=null){
            this.sortedHash.newMsgCallback = callback
        }
    }
    public setServerAckCallback(callback:ServerAckCallback){
        if(this.sortedHash!=null){
            this.sortedHash.onServerAckCallback = callback
        }
    }
    public setRemoveCallback(callback:ServerAckCallback){
        if(this.sortedHash!=null){
            this.sortedHash.onRemoveCallback = callback
        }
    }

    public close(){
        this.sortedHash= null;
    }
}
export default MessageBus
